
#include "RealTimeDealCache.h"
#include <map>

namespace detail{
	RealTimeDealCache::RealTimeDealCache(int64_t state) :
		m_id_start(-1), 
		m_id_end(-1), 
		m_capcity(32),
		m_state_id(state)
	{

	}

	RealTimeDealCache::~RealTimeDealCache()
	{
		for (RecordVecList::iterator it = m_records.begin(); it != m_records.end(); ++it)
		{
			RecordBatch* batch = *it;
			if (batch){ batch->clear(); delete batch; }
		}
		m_records.clear();
	}

	void RealTimeDealCache::Add(int id, const Record* record)
	{
		if (!m_records.empty())
		{
			RecordBatch* last = m_records.back();
			if (last->m_batch == id)
			{
				//BASSERTS(!last->empty(), "");
				last->push_back(*record);
				return;
			}
		}

		RecordBatch* batch = NULL;
		if ((int)m_records.size() >= m_capcity)
		{
			//BASSERTS(m_id_start < m_id_end && m_id_start >= 0, "");
			batch = m_records.front();
			m_records.pop_front();
			batch->clear();
			RecordBatch* next = m_records.front();
			m_id_start = next->m_batch;
		}
		else
		{
			batch = new RecordBatch();
		}
		batch->m_batch = id;
		batch->push_back(*record);
		m_records.push_back(batch);

		if (m_id_end < 0)
		{
			m_id_start = m_id_end = id;
		}
		else if (m_id_end < id)
			m_id_end = id;
	}


	bool RealTimeDealCache::GetSince(int id, Callback& callback)
	{
		// 用于枚举从id到最新m_batchid的所有Records
		//BASSERT(id <= m_id_end);

		// 应该先将要删除的记录找到,全部删除,然后在逐个添加
		// 因为RealTimeDealList中的m_values会将要删除的记录保留,其m_dealStatus为>=4
		// 而ui中的对应key会依旧存在,不删除,最终插入记录,会在m_values中找到,但值已经更新

		class OverlaySplitList{
			struct RecordInfo{
				RecordBatch*	batch;
				int				index;		// RecordBatch中的索引
				int				batchid;	// RecordBatch的成员
				int				sortid;
				bool			remove;	// rd.m_body.m_dealStatus >=4
			public:
				bool operator<(const RecordInfo& rhs)const{ return sortid < rhs.sortid; }
			};
			typedef std::vector<RecordInfo> RecordInfoVec;
			typedef std::map<std::string, RecordInfo> RecordInfoMap;
			RecordInfoMap	m_infomap;
			int				m_nextid;
		public:
			OverlaySplitList() :m_nextid(0){}
			void AddRecordInfo(RecordBatch* batch, int index,bool remove)
			{
				// 保证DealIndex不重复
				//BASSERTS(batch && index >= 0 && index < (int)batch->size(), "");
				const MarketStreamInfo& info = batch->at(index);
				std::string key(info.m_body.m_id);
				RecordInfoMap::iterator it = m_infomap.find(key);
				if (it != m_infomap.end())
				{
					RecordInfo& ri = it->second;
					ri.batch = batch; ri.batchid = batch->m_batch; ri.index = index;
					ri.remove = remove;
					ri.sortid = m_nextid++;
				}
				else
				{
					RecordInfo ri;
					ri.batch = batch; ri.batchid = batch->m_batch; ri.index = index;
					ri.remove = remove;
					ri.sortid = m_nextid++;
					m_infomap[key] = ri;
				}
			}
			void SplitRemovedAdded(RealTimeDealCache::Callback& callback)
			{
				RecordInfoVec all; all.reserve(m_infomap.size());
				for (RecordInfoMap::iterator it = m_infomap.begin(); it != m_infomap.end();++it)
				{
					const RecordInfo& ri = it->second;
					all.push_back(ri);
				}
				if (all.size() > 1)
				{
					std::sort(all.begin(), all.end());
				}

				RecordInfoVec removed;
				RecordInfoVec added;
				for (int i = 0; i < (int)all.size(); i++)
				{
					if (all[i].remove)removed.push_back(all[i]);
					else added.push_back(all[i]);
				}

				// 先删除,后追加
				for (int i = 0; i < (int)removed.size(); i++)
				{
					const RecordInfo& ri = removed[i];
					callback.OnRecord(ri.batch->m_batch, &ri.batch->at(ri.index));
				}
				for (int i = 0; i < (int)added.size(); i++)
				{
					const RecordInfo& ri = added[i];
					if (!callback.OnRecord(ri.batch->m_batch, &ri.batch->at(ri.index)))
						break;
				}
			}
		};
		OverlaySplitList splitList;
		// 第一步定位到比id大的位置,后续可以使用哈希表来加速
		RecordVecList::iterator it = m_records.begin();
		for (; it != m_records.end(); it++)
		{
			RecordBatch* batch = *it;
			if (batch->m_batch <= id)
				continue;
			for (int i = 0; i < (int)batch->size(); i++)
			{
				const Record& rd = batch->at(i);
				int nDealStatus = atoi(rd.m_body.m_dealStatus);
				splitList.AddRecordInfo(batch, i, nDealStatus >= 4 && nDealStatus!=8);
			}
		}
		splitList.SplitRemovedAdded(callback);
		return true;
	}

}